package main

import (
    "../medusa"
    "../msgcode"
    "fmt"
)

//==============================================================
//Acceptor: World
//==============================================================

type World struct {
    medusa.TcpAcceptor

    pack_idle *medusa.Packet
}

func NewWorld(listener medusa.Listener, uuid int) *World {

    acc := new(World)
    acc.Constructor(listener, uuid)

    return acc
}

func (self *World) Constructor(listener medusa.Listener, uuid int) {
    self.pack_idle = medusa.NewPacket(msgcode.IN_ECHO)
    self.TcpAcceptor.Constructor(listener, uuid,
        //event callback: OnIdle        
        func() {
            self.SendPacket(self.pack_idle)
        },

        //event callback: PreOnSent    
        func(pack *medusa.Packet) {

        },

        //event callback: ConnectionLose
        func() {
            //self.Error("World------Event_ConnectionLose---------in")
            if self == Global().World() {
                Global().SetWorld(nil) //free world's uuid,reload to free_uuid queue
                Global().GateServer().CloseAllAcceptor()
                self.Warning("------------WorldServer Closed!!!!: (uuid:<%d>: %v <+ %v)\n",
                    self.GetUUID32(), self.GetLocalAddr(), self.GetRemoteAddr())
            }
            //self.Error("World------Event_ConnectionLose---------out")
        },

        //event callback: UnknowPacketReceived 
        func(pack *medusa.Packet) {
            self.Stack("Event_UnknowPacketReceived---------in:des:%v", pack.Des)
            //self.Stack("Client-->World: des:%v(uuid:<%d>: %v <+ %v)", pack.Des, 
            //self.GetUUID32(), self.GetLocalAddr(), self.GetRemoteAddr())
            Global().SmartSend(pack)
            self.Stack("Event_UnknowPacketReceived---------out")
        })  // end: Constructor)

    //init methods
    self.init_methods()

    //init protocol
    self.init_protocol()
}

//--------------------------------------------------------------
//World: methods
//--------------------------------------------------------------
//World: internal implements
func (self *World) init_methods() {

    self.AddMethod("add", func(args ...interface{}) (result interface{}, err error) {
        a := args[0].(int)
        b := args[1].(int)
        result = a + b
        return
    })

    //your code

}

//World: external inteface
func (self *World) Add(a, b int) {
    c, err := self.CallMethod("add", a, b)
    if err == nil {
        fmt.Printf("%v + %v = %v\n", a, b, c.(int))
    } else {
        fmt.Printf(err.Error())
    }

}

//--------------------------------------------------------------
//World: network protocol
//--------------------------------------------------------------
func (self *World) init_protocol() {
    //内部协议
    self.AddProtocol(msgcode.IN_ECHO, func(pack *medusa.Packet) {
        //self.Stack("Wrold.IN_ECHO---------in")
        self.Success("remote is alive! (uuid:<%d>: %v <- %v)", self.GetUUID32(), self.GetLocalAddr(), self.GetRemoteAddr())
        //self.Stack("World.IN_ECHO---------out")
    })

    self.AddProtocol(msgcode.IN_I_AM_WORLD, func(pack *medusa.Packet) {
        self.Stack("msgcode.IN_I_AM_WORLD---------in")

        if Global().World() == nil {
            self.Success("IN_I_AM_WORLD: (uuid:<%d>: %v <- %v)\n", self.GetUUID32(), self.GetLocalAddr(), self.GetRemoteAddr())
            Global().SetWorld(self)
            self.SendPacket(pack)
        } else {
            if Global().World() != self {
                self.Error("IN_I_AM_WORLD: but WorldServer is exist: (uuid:<%d>: %v <- %v)\n",
                    self.GetUUID32(), self.GetLocalAddr(), self.GetRemoteAddr())
                self.Close()
            } else {
                //心跳包而已
            }

        }
        self.Stack("msgcode.IN_I_AM_WORLD---------out")
    })

    self.AddProtocol(msgcode.IN_INTO_SPACE, func(pack *medusa.Packet) {
        self.Stack("msgcode.IN_INTO_SPACE---------in")

        space_uuid := pack.ReadInt32LE()
        client_uuid := pack.ReadInt32LE()
        Global().GateServer().IntoSpace(space_uuid, client_uuid)
        self.Stack("msgcode.IN_INTO_SPACE---------out")
    })

    self.AddProtocol(msgcode.IN_LEAVE_SPACE, func(pack *medusa.Packet) {
        self.Stack("msgcode.IN_LEAVE_SPACE---------in")

        space_uuid := pack.ReadInt32LE()
        client_uuid := pack.ReadInt32LE()
        Global().GateServer().LeaveSpace(space_uuid, client_uuid)
        self.Stack("msgcode.IN_LEAVE_SPACE---------out")
    })

    self.AddProtocol(msgcode.IN_CLEAR_SPACE, func(pack *medusa.Packet) {
        self.Stack("msgcode.IN_CLEAR_SPACE---------in")

        space_uuid := pack.ReadInt32LE()
        Global().GateServer().ClearSpace(space_uuid)
        self.Stack("msgcode.IN_CLEAR_SPACE---------out")
    })

    self.AddProtocol(msgcode.IN_CLIENT_DISCONNECT, func(pack *medusa.Packet) {
        self.Stack("msgcode.IN_CLIENT_DISCONNECT---------in")

        client_uuid := pack.ReadInt32LE()
        Global().GateServer().CloseAcceptor((int)(client_uuid))
        self.Stack("msgcode.IN_CLIENT_DISCONNECT---------out")
    })
}

//==============================================================
//Listener: MyListener
//==============================================================
type WorldService struct {
    medusa.TcpListener
}

func NewWorldService(name string, max_conn int,
    rcv_buf int, snd_buf int, sndchan int, max_idle_sec int64, log medusa.Log) *WorldService {

    listen := new(WorldService)
    listen.Constructor(name, max_conn, rcv_buf, snd_buf, sndchan, max_idle_sec, log)

    return listen
}

func (self *WorldService) Constructor(name string, max_conn int,
    rcv_buf int, snd_buf int, sndchan int, max_idle_sec int64,
    log medusa.Log) {

    self.TcpListener.Constructor(name, max_conn, rcv_buf, snd_buf, sndchan, max_idle_sec, log,

        //event callback: gen uuid 
        nil,
        /*
           func() int {
           return self.DefaultGenUUID ()
           },*/

        //event callback: create connection object
        func(uuid int) medusa.Acceptor {
            return NewWorld(self, uuid)
        },

        //event callback: connection made 
        func(acc medusa.Acceptor) {
            self.Stack("Event_ConnectionMade---------in")

            self.Stack("Event_ConnectionMade---------out")
        },

        //event callback: connection lose 
        func(acc medusa.Acceptor) {
            self.Stack("Event_ConnectionLose---------in")

            self.Stack("Event_ConnectionLose---------out")
        })  // end: medusa.NewListener

    //init methods
    self.init_methods()
}

//--------------------------------------------------------------
//MyListener: methods
//--------------------------------------------------------------
//MyListener: internal implements
func (self *WorldService) init_methods() {

    self.AddMethod("add", func(args ...interface{}) (result interface{}, err error) {
        a := args[0].(int)
        b := args[1].(int)
        result = a + b
        return
    })

    //your code

}

//MyListener: external inteface
func (self *WorldService) Add(a, b int) {
    c, err := self.CallMethod("add", a, b)
    if err == nil {
        fmt.Printf("%v + %v = %v\n", a, b, c.(int))
    } else {
        fmt.Printf(err.Error())
    }

}
